package zutils

import (
	farmhash "github.com/leemcloughlin/gofarmhash"
	"sync"
	"unsafe"
)

//仿照Java的concurrenthashmap自行实现的GO支持并发读写的map
type ConcurrentHashMap[T comparable] struct {
	maps []map[T]any
	seg int
	locks []sync.RWMutex
	seed uint32
}

func NewConcurrentHashMap[T comparable](seg, cap int) *ConcurrentHashMap[T] {
	maps := make([]map[T]any, seg)
	locks := make([]sync.RWMutex, seg)
	for i := 0; i < seg; i++ {
		maps[i] = make(map[T]any, cap / seg)
		locks[i] = sync.RWMutex{}
	}

	return &ConcurrentHashMap[T]{
		maps: maps,
		seg: seg,
		seed: 0,
		locks: locks,
	}
}

func Pointer2Int[T comparable](p *T) int {
	return *(*int)(unsafe.Pointer(p))
}

func (m *ConcurrentHashMap[T]) getSegIndex(key T) int {
	hash := int(farmhash.Hash32WithSeed(IntToBytes(Pointer2Int(&key)), m.seed))
	return hash % m.seg
}

func (m *ConcurrentHashMap[T]) Set(key T, value any) {
	index := m.getSegIndex(key)
	m.locks[index].Lock()
	defer m.locks[index].Unlock()
	m.maps[index][key] = value
}

func (m *ConcurrentHashMap[T]) Get(key T) (any, bool){
	index := m.getSegIndex(key)
	m.locks[index].RLock()
	defer m.locks[index].RUnlock()
	value, exists := m.maps[index][key]
	return value, exists
}

func (m *ConcurrentHashMap[T]) GetSize() int {
	size := 0
	for index := range m.maps {
		size += len(m.maps[index])
	}
	return size
}

func (m *ConcurrentHashMap[T]) Remove(key T) {
	index := m.getSegIndex(key)
	m.locks[index].Lock()
	defer m.locks[index].Unlock()
	delete(m.maps[index], key)
}

func (m *ConcurrentHashMap[T]) GetAllValues() []any {
	resultSlice := make([]any, 0)
	for index := range m.maps {
		for key := range m.maps[index] {
			resultSlice = append(resultSlice, m.maps[index][key])
		}
	}
	return resultSlice
}

func (m *ConcurrentHashMap[T]) Clear() {
	for index := range m.maps {
		for key := range m.maps[index] {
			delete(m.maps[index], key)
		}
	}
}